package com.project.common.configuration;

import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.project.biz.RedisBiz;
import com.project.common.filter.AllRequestFilter;
import com.project.common.filter.CorsFilter;
import com.project.common.filter.LoginFilter;
import com.project.common.filter.XssFilter;
import com.project.common.resolvers.LanguageLocaleResolverConfig;
import com.project.common.resolvers.UserArgumentResolver;
import com.project.common.xss.XssStringJsonSerializer;
import org.hibernate.validator.HibernateValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.*;

import javax.servlet.Filter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

@Configuration
public class WebConfiguration implements WebMvcConfigurer {

    /**
     * 用户缓存信息
     */
    @Autowired
    private RedisBiz redisBiz;

    /**
     * 添加自定义拦截器
     * @param interceptorRegistry
     */
    @Override
    public void addInterceptors(InterceptorRegistry interceptorRegistry) {

    }

    /**
     * 设置静态资源处理器
     * @param resourceHandlerRegistry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry resourceHandlerRegistry) {
        resourceHandlerRegistry.addResourceHandler("/static/**").
                addResourceLocations("classpath:/");
        resourceHandlerRegistry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        resourceHandlerRegistry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    /**
     * 跨域设置
     * @param corsRegistry
     */
    @Override
    public void addCorsMappings(CorsRegistry corsRegistry) {
        corsRegistry.addMapping("/**")
                .allowedOrigins("*")
                .allowedHeaders("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .maxAge(3600*24);
    }

    /**
     * 配置消息转换器
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        /**
         * 使用Jackson序列化
         */
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        //处理中文乱码问题
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);

        ObjectMapper objectMapper = new ObjectMapper();
        //收到未定义参数时不报异常
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        //收到Bean中未定义的参数时不报异常
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //大小写脱敏 默认为false  需要改为true
        objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES,true);
        //注册xss解析器
        SimpleModule xssModule = new SimpleModule("XssStringJsonSerializer");
        xssModule.addSerializer(new XssStringJsonSerializer());
        objectMapper.registerModule(xssModule);

        // 自定义日期的格式
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        // 返回时间格式使用时间戳
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);

        //返回数据中的NULL做处理,根据不同数据类型返回对应空时的默认值
        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object paramT, JsonGenerator paramJsonGenerator, SerializerProvider paramSerializerProvider) throws IOException {
                String fieldName = paramJsonGenerator.getOutputContext().getCurrentName();
                try {
                    //反射获取字段类型
                    Field field = paramJsonGenerator.getCurrentValue().getClass().getDeclaredField(fieldName);
                    if (Objects.equals(field.getType(), String.class)) {
                        //字符串型空值""
                        paramJsonGenerator.writeString("");
                        return;
                    } else if (Objects.equals(field.getType(), List.class)) {
                        //列表型空值返回[]
                        paramJsonGenerator.writeStartArray();
                        paramJsonGenerator.writeEndArray();
                        return;
                    } else if (Objects.equals(field.getType(), Map.class)) {
                        //map型空值返回{}
                        paramJsonGenerator.writeStartObject();
                        paramJsonGenerator.writeEndObject();
                        return;
                    } else if (Objects.equals(field.getType(), Date.class)) {
                        //Date型空值返回 null
                        paramJsonGenerator.writeNull();
                        return;
                    } else  if (Objects.equals(field.getType(), Long.class)) {
                        //Long型空值返回 null
                        paramJsonGenerator.writeNull();
                        return;
                    } else  if (Objects.equals(field.getType(), Integer.class)) {
                        //Integer型空值返回 null
                        paramJsonGenerator.writeNull();
                        return;
                    }
                } catch (NoSuchFieldException e) {
                    try {
                        if (null != paramJsonGenerator.getCurrentValue().getClass().getSuperclass()){
                            Field field = paramJsonGenerator.getCurrentValue().getClass().getSuperclass().getDeclaredField(fieldName);
                            if (Objects.equals(field.getType(), Map.class)) {
                                //map型空值返回{}
                                paramJsonGenerator.writeStartObject();
                                paramJsonGenerator.writeEndObject();
                                return;
                            } else if (Objects.equals(field.getType(), String.class)) {
                                //字符串型空值""
                                paramJsonGenerator.writeString("");
                                return;
                            } else if (Objects.equals(field.getType(), List.class)) {
                                //列表型空值返回[]
                                paramJsonGenerator.writeStartArray();
                                paramJsonGenerator.writeEndArray();
                                return;
                            } else  if (Objects.equals(field.getType(), Date.class)) {
                                //Date型空值返回 null
                                paramJsonGenerator.writeNull();
                                return;
                            } else  if (Objects.equals(field.getType(), Integer.class)) {
                                //Integer型空值返回 null
                                paramJsonGenerator.writeNull();
                                return;
                            } else  if (Objects.equals(field.getType(), Long.class)) {
                                //Long型空值返回 null
                                paramJsonGenerator.writeNull();
                                return;
                            }
                        }
                    } catch (NoSuchFieldException e1) {

                    }
                }
                //默认返回""
                paramJsonGenerator.writeString("");
            }
        });

        //Long、BigDecimal类型转为String类型
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);

        converter.setObjectMapper(objectMapper);
        converter.setSupportedMediaTypes(fastMediaTypes);
        converters.add(converter);

        /**
         * 使用FastJson序列化
         */
//        FastJsonHttpMessageConverter converter2 = new FastJsonHttpMessageConverter();
//        //设置默认字符集编码格式
//        converter.setDefaultCharset(StandardCharsets.UTF_8);
//
//        //添加fastJson的配置信息，比如：是否要格式化返回的json数据;
//        FastJsonConfig fastJsonConfig = new FastJsonConfig();
//
//        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat,
//                SerializerFeature.QuoteFieldNames,                  //输出key时是否使用双引号
//                SerializerFeature.WriteMapNullValue,                //是否输出值为null的字段
//                SerializerFeature.WriteNullStringAsEmpty,           //字符类型字段如果为null,输出为"",而非null
//                SerializerFeature.DisableCircularReferenceDetect,   //关闭循环引用
//                //SerializerFeature.WriteDateUseDateFormat,         //时间格式化
//                SerializerFeature.WriteNullListAsEmpty              //List字段如果为null,输出为[],而非null
//        );
//
//        // Long、BigDecimal类型转为String类型返回
//        SerializeConfig serializeConfig = SerializeConfig.globalInstance;
//        serializeConfig.put(Long.class , com.alibaba.fastjson.serializer.ToStringSerializer.instance);
//        serializeConfig.put(Long.TYPE , com.alibaba.fastjson.serializer.ToStringSerializer.instance);
//        serializeConfig.put(BigDecimal.class, com.alibaba.fastjson.serializer.ToStringSerializer.instance);
//        fastJsonConfig.setSerializeConfig(serializeConfig);
//
//        converter2.setFastJsonConfig(fastJsonConfig);
//
//        //将convert添加到converters当中,并添加在最前列,因为Springboot2默认首先加载使用的是MappingJackson2HttpMessageConverter
//
//        converters.add(0, converter);
    }

    /**
     * 自定义参数解析
     * @param list
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> list) {
        list.add(new UserArgumentResolver());
    }

    /**
     * 匹配路由请求规则
     * @param pathMatchConfigurer
     */
    @Override
    public void configurePathMatch(PathMatchConfigurer pathMatchConfigurer) {

    }

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer contentNegotiationConfigurer) {

    }

    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer asyncSupportConfigurer) {

    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer defaultServletHandlerConfigurer) {

    }

    /**
     * 自定义转化器
     * @param formatterRegistry
     */
    @Override
    public void addFormatters(FormatterRegistry formatterRegistry) {

    }

    /**
     * 添加自定义视图控制器
     * @param viewControllerRegistry
     */
    @Override
    public void addViewControllers(ViewControllerRegistry viewControllerRegistry) {

    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry viewResolverRegistry) {

    }

    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> list) {

    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> list) {

    }

    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> list) {

    }

    @Override
    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> list) {

    }

    @Override
    public Validator getValidator() {
        return null;
    }

    @Override
    public MessageCodesResolver getMessageCodesResolver() {
        return null;
    }

    /**
     * 跨域设置
     * @return
     */
    @Bean(name = "CorsFilter")
    public FilterRegistrationBean filter0_CorsFilter(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        Filter filter = new CorsFilter();
        filterRegistrationBean.setFilter(filter);
        //设置拦截路径
        ArrayList<String> urls = new ArrayList<>();
        urls.add("/*");
        filterRegistrationBean.setUrlPatterns(urls);
        //如果多个Filter,指定Filter的顺序,数字越小越先开始
        filterRegistrationBean.setOrder(1);
        return filterRegistrationBean;
    }

    /**
     * 系统统一拦截认证
     * @return
     */
    @Bean(name = "AllRequestFilter")
    public FilterRegistrationBean allRequestFilterRegistrationBean(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new AllRequestFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setOrder(2);
        return filterRegistrationBean;
    }

    /**
     * 登陆拦截认证
     * @return
     */
    @Bean(name = "LoginFilter")
    public FilterRegistrationBean oginFilterRegistrationBean(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new LoginFilter(redisBiz));
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setOrder(3);
        return filterRegistrationBean;
    }

    /**
     * SXX防护
     * @return
     */
    @Bean(name = "XssFilter")
    public FilterRegistrationBean sxxFilterRegistrationBean(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new XssFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setOrder(4);
        return filterRegistrationBean;
    }

    /**
     * 分页拦截器
     * @return
     */
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }

    /**
     * 注入i18n
     * @return new LanguageLocaleResolverConfig()
     */
    @Bean
    public LocaleResolver localeResolver() {
        return new LanguageLocaleResolverConfig();
    }

    @Bean
    public ResourceBundleMessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setDefaultEncoding("UTF-8");
        messageSource.setBasenames("i18n/messages", "i18n/ValidationMessages");
        return messageSource;
    }

    /**
     * Validator验证增加国际化配置
     * @return
     */
    @Bean
    public LocalValidatorFactoryBean validator() {
        LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
        validator.setProviderClass(HibernateValidator.class);
        validator.setValidationMessageSource(messageSource());
        return validator;
    }
}
